package com.tuo51.evaluate.service.impl;

import com.alibaba.fastjson.JSON;
import com.aspose.words.Document;
import com.google.common.collect.ImmutableMap;
import com.matt.Application;
import com.matt.commons.dto.sso.StaffDTO;
import com.matt.commons.exception.BusinessException;
import com.matt.foundation.dto.AreaDetailDTO;
import com.matt.foundation.model.ErrorCode;
import com.matt.foundation.model.UnionTypeID;
import com.matt.service.remoteCall.SsoCallService;
import com.tuo51.components.redis.RedisService;
import com.tuo51.evaluate.domain.etc.MailRecord;
import com.tuo51.evaluate.domain.evaluatingV2.EvaluateV2Record;
import com.tuo51.evaluate.domain.evaluatingV2.EvaluateV2RecordDimensionScore;
import com.tuo51.evaluate.domain.export.EvaluateExportRecord;
import com.tuo51.evaluate.repositories.MailRecordRepository;
import com.tuo51.evaluate.repositories.export.EvaluateExportRecordRepository;
import com.tuo51.evaluate.service.*;
import com.tuo51.evaluate.service.mail.MailService;
import com.tuo51.evaluate.vo.evaluate.EvaluateV2AnswerVO;
import com.tuo51.foudation.constant.ChannelConfig;
import com.tuo51.foudation.utils.CopyUtils;
import com.tuo51.foudation.utils.DateUtil;
import com.tuo51.foudation.utils.EvaluationReportUtils;
import com.tuo51.foudation.utils.export.HealthReportUtil;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateNotFoundException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.tuo51.foudation.constant.RedisConstant.EMAIL_ADDRESS_EXPIRED_TIME;
import static com.tuo51.foudation.constant.RedisConstant.EMAIL_REPORT_EXPIRED_TIME;
import static freemarker.template.Configuration.VERSION_2_3_26;

@Service
public class EvaluateV2ExportServiceImpl implements EvaluateV2ExportService {

    @Autowired
    EvaluateExportRecordRepository exportRecordRepository;

    @Autowired
    MailRecordRepository mailRecordRepository;

    @Autowired
    EvaluateUploadService evaluateUploadService;

    @Autowired
    RemoteChartService remoteChartService;

    @Autowired
    private EvaluateV2Service evaluateService;

    @Autowired
    private EvaluateV2ConclusionService conclusionService;

    @Autowired
    private SsoCallService ssoCallService;

//    @Autowired
//    private EvaluateStaffService evaluateStaffService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private MailService mailService;

    private static Configuration configuration = null;

    //临时文件写出路径
    private static String tempPath = null;

    //初始化
    static {
        if(File.separatorChar == '/'){
            tempPath =  "/tmp/evaluate_report";
        }else {
            tempPath =  "d:";
        }
    }

    //
    static {
        try {
            configuration = new Configuration(VERSION_2_3_26);
            configuration.setDefaultEncoding("utf-8");
            configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
            TemplateLoader tl = new ClassTemplateLoader(Application.class,"/");
            configuration.setTemplateLoader(tl);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String safeXML(String str){
        return str.replaceAll("\\<", "&lt;").replaceAll("\\>", "&gt;");
    }

    public static final String SkipDimensionID = "2c92848567977b50016797a129d909b4";

    @Override
    public String exportEvaluateWordReport(String channel, EvaluateV2Record record, StaffDTO staff, AreaDetailDTO areaDetail) {
        return exportEvaluateReport(channel, record, staff, areaDetail, ExportType.WORD);
    }

    @Override
    public String exportEvaluateReport(String channel, EvaluateV2Record record, StaffDTO staff, AreaDetailDTO area,  ExportType exportType){
        //create folder
        File tf = new File(tempPath);
        if(!tf.exists()){
            Boolean success = tf.mkdirs();
            if(success){
                System.out.println("create file success::" + tempPath);
            }
        }

        String tempFilePath = tempPath + File.separatorChar + record.getId() +"_evaluateV2.tmp";
        Writer out = null;
        try {
            //生成文档
            Template temple = null;
            String templateName = exportType.getTemplateName();
            if(StringUtils.isNotEmpty(channel)){
                templateName = templateName  + "_" + channel;
            }

            try {
                temple = configuration.getTemplate(templateName);//获取模板
            }catch (TemplateNotFoundException e){
                temple = configuration.getTemplate(exportType.getTemplateName());
            }

            out = new OutputStreamWriter(new FileOutputStream(tempFilePath));//生成最终页面并写到文件

            Map data = CopyUtils.transBean2Map(record);

            //处理渲染数据
            {
                data.put("hightLevelItems", EvaluationReportUtils.generateHighLevelItems(record.getHighLevelInfo()));

                //处理培养建议
                List games = EvaluationReportUtils.generateBringUpList(record.getHighLevelInfo());
                if(games != null && games.size() > 0){
                    data.put("games", games);
                }

                //deprecated it
                //TODO: 需要幼儿园信息
//                Organization org = evaluateStaffService.staffOrgnization(staff);
                data.put("areaName", area.getName());
                data.put("areaAddress", area.getAddress());
                data.put("areaPhone", area.getContactNumber());
//                data.put("areaName", staff.getExtInfo().getAreaName());
//                data.put("areaAddress", staff.getExtInfo().getAreaAddress());
//                data.put("areaPhone", staff.getExtInfo().getAreaPhone());

            }

            double height = 0;
            double weight = 0;
            double header = 0;
            float actualMonth = (float) DateUtil.betweenMonthsV2(record.getEvaluatingDate(), record.getBirthday());

            if(StringUtils.isNotBlank(record.getHeight()) &&  StringUtils.isNotBlank(record.getWeight()) ) {
                height = Double.parseDouble(record.getHeight());
                weight = Double.parseDouble(record.getWeight());
                header = StringUtils.isNotBlank(record.getHeader()) ? Double.parseDouble(record.getHeader()) : 0;
            }else {
                 if(height <= 0.01 || weight <= 0.01){
                    throw new BusinessException(ErrorCode.VERSION_ERROR, "不正确的儿保测评身高体重");
                }
            }

            String gender = record.getGender() == 0 ? "女" : "男";

            //仅word需要静态报表图片
            if (exportType == ExportType.WORD) {
                //生成身高报表图表
                String heightImg = HealthReportUtil.encodedHeightChart(gender, actualMonth, (float) height);

                //生成体重图表
                String weightImg = HealthReportUtil.encodedWeightChart(gender, actualMonth, (float) weight);

                //img
                data.put("heightImg", heightImg);
                data.put("weightImg", weightImg);

                //测评柱状图
                float em = 0;   //计算智龄
                float dq = 0;   //计算发育商
                int dimensionAvgCount = 0;

                //创建图表
                Double [] barValues = new Double[7];
                Double [] lineValues = new Double[7];
                String [] names = new String[7];
                for(int i = 0 ; i < lineValues.length && i < record.getDimensionScores().size(); i++){
                    EvaluateV2RecordDimensionScore c = record.getDimensionScores().get(i);
                    lineValues[i] = c.getMonth() * 1.0 / 10.0;
                    barValues[i] = c.getDq() * 1.0 / 10.0;
                    names[i] = c.getDimensionName();

                    if(c.getDimensionId().equals(SkipDimensionID)) {

                    }else{
                        dimensionAvgCount += 1;
                        em += lineValues[i];
                        dq += barValues[i];
                    }
                }
                //
                dq = dq / dimensionAvgCount;
                em = em / dimensionAvgCount;

                data.put("eMonthVal", em);
                data.put("dqVal", dq);

                data.put("eMonth", String.format("%.1f", em));
                data.put("dq", String.format("%.1f", dq));

                data.put("emValues", lineValues );
                data.put("dqValues", barValues);
                data.put("dNames", names);


                Double[] chartValues = new Double[]{barValues[0],barValues[1],barValues[2],barValues[3],barValues[4], dq + 0.0};
                String evaluateImg = remoteChartService.getRemoteEvaluateChartBase64(chartValues);
                data.put("evaluateImg", evaluateImg);
            }

            //生成结论文本
            String heightConclusion = HealthReportUtil.heightConclusion(record.getChildrenName(), gender, height, record.getMonth());
            String weightConclusion = HealthReportUtil.weightConclusion(record.getChildrenName(), gender, height, weight, record.getMonth());

            //heightConclusion
            //weightConclusion
            data.put("heightConclusion", safeXML(heightConclusion));
            data.put("weightConclusion", safeXML(weightConclusion));

            //base info
            data.put("weight", weight);
            data.put("height", height);
            data.put("header", header);

            //扩展结论数据
            Map result = conclusionService.generateReportExtInfo(record);
            data.putAll(result);

            //答案表
            List<EvaluateV2AnswerVO> answerSheet = (List<EvaluateV2AnswerVO>) data.get("answerSheet");

            //分组答案表
            List grouped = new ArrayList();
            List<EvaluateV2AnswerVO> group = null;
            String groupName = null;
            for (EvaluateV2AnswerVO answer : answerSheet){
                if(group == null || !answer.getDimensionName().equals(groupName)){
                    group = new ArrayList<>();
                    groupName = answer.getDimensionName();
                    grouped.add(group);
                }

                group.add(answer);
            }

            data.put("groupedAnswers", grouped);

            //仅h5需要这个
            if (exportType == ExportType.H5) {
                data.put("jsonDetail", JSON.toJSONString(data));
            }

            temple.process(data, out);//处理

            return tempFilePath;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {

            }

        }

        return  null;
    }

    @Override
    public String exportEvaluateWordReportToOSS(String channel, String evaluateRecordId, StaffDTO staff, AreaDetailDTO area) {
        return exportEvaluateReportToOSS(channel, evaluateRecordId, staff, area, ExportType.WORD, false);
    }

    @Override
    public String exportEvaluateWordReportToOSS(String channel, String evaluateRecordId, StaffDTO staff, AreaDetailDTO area, boolean force) {
        return exportEvaluateReportToOSS(channel, evaluateRecordId, staff, area, ExportType.WORD, force);
    }

    @Override
    public String exportEvaluateReportToOSS(String channel, String evaluateRecordId, StaffDTO staff, AreaDetailDTO area, ExportType exportType) {
        return exportEvaluateReportToOSS(channel, evaluateRecordId, staff, area, exportType, false);
    }

    public String exportEvaluateReportToOSS(String channel, String evaluateRecordId, StaffDTO staff, AreaDetailDTO area, ExportType exportType, boolean force){
        EvaluateExportRecord exportRecord = exportRecordRepository.findByTypeID(UnionTypeID.of(evaluateRecordId, exportType.getType()));
        if(exportRecord != null){
            return exportRecord.getStaticURL();
        }

        EvaluateV2Record record = evaluateService.getEvaluateDetail(evaluateRecordId);
        if(record == null){
            throw  new BusinessException(ErrorCode.EVALUATE_RECORD_NOT_EXIST, "报告不存在");
        }

        if( force == false && !record.getPaid() ){
            throw  new BusinessException(ErrorCode.REPORT_PAID_NEEDED, "报告没有付费，无法导出");
        }

        String tempFilePath = exportEvaluateReport(channel, record, staff, area, exportType);

        if (exportType == ExportType.WORD){
            //处理成真的doc
            String tt = convertXmlToDoc(tempFilePath);
            if (StringUtils.isNotEmpty(tt)){
                tempFilePath = tt;
            }
        }

        String ossFile = evaluateUploadService.uploadLocalFile(tempFilePath, exportType, record.getChildrenName()+"宝宝的报告");

        //保存
        if(StringUtils.isNotEmpty(ossFile)) {
            exportRecord = EvaluateExportRecord.of(exportType.getType(), record.getId(), ossFile);
            exportRecordRepository.save(exportRecord);
            return ossFile;
        }else{
            throw  new BusinessException(ErrorCode.ERROR, "导出失败");
        }
    }

    private String convertXmlToDoc(String docFile) {

        try {
            // Open a document.
            Document doc = new Document(docFile);
            // Save document.
            String outputFileName = docFile + ".doc";

            doc.save(outputFileName);

            return outputFileName;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public String exportWordComparingReportToOSS(String channel, String evaluateRecordId, String comparingRecordId, StaffDTO staff){
        return null;
    }

    @Override
    public String uploadReportToOSSAsWord(StaffDTO staff, AreaDetailDTO area, String evaluateRecordId, String channel){

        //导出
        String exported_file = exportEvaluateWordReportToOSS(channel, evaluateRecordId, staff, area);

        //发送报告
        return exported_file;
    }

    @Override
    public Map mailReportAsWord(StaffDTO staff, AreaDetailDTO area, String evaluateRecordId, String mailAddress, String channel){

        String key1 = "RECORD_EMAIL_" + evaluateRecordId;
        String key2 = "RECORD_EMAIL_" + mailAddress.trim();

        String value1 = redisService.getValue(key1);
        String value2 = redisService.getValue(key2);

        if (value1 != null){
            throw new BusinessException(ErrorCode.EMAIL_RATE_UNEXPECTED, "报告已发送到邮箱" + value1 + "，若长时间没有收到邮件，请更换收件地址。");
        }
        if (value2 != null){
            throw new BusinessException(ErrorCode.EMAIL_RATE_UNEXPECTED, "您的邮箱收件频率过高，请稍后再试。");
        }

        EvaluateV2Record evaluateRecord = evaluateService.getEvaluateDetailForStaff(evaluateRecordId, staff.getId());

        if (evaluateRecord == null){
            throw new BusinessException(ErrorCode.EVALUATE_RECORD_NOT_EXIST, "测评报告不存在");
        }

        //导出
        String exported_file = exportEvaluateWordReportToOSS(channel, evaluateRecordId, staff, area);

        //发送报告
        String reportNameTail = "测评报告";
        ChannelConfig cc = ChannelConfig.forChannel(channel);
        if (StringUtils.isNotEmpty(cc.getReportNameTail())){
            reportNameTail = cc.getReportNameTail();
        }

        String subject = evaluateRecord.getChildrenName() + "的" + reportNameTail + "  报告创建时间:" + DateUtil.parseToDateTime(evaluateRecord.getEvaluatingDate());
        String content = "<h1>请点击如下链接下载 "+evaluateRecord.getChildrenName()+"宝贝 的" + reportNameTail + "</h1>" +
                String.format("<a href='%s'><h3><b>&gt;点击下载&lt;</b></h3></a>", exported_file);

        Map result = null;
        String failedReason = null;
        try {
            mailService.sendDirectMail(mailAddress, subject, content, channel);
            //写redis
            redisService.saveValue(key1, EMAIL_REPORT_EXPIRED_TIME, mailAddress.trim());
            redisService.saveValue(key2, EMAIL_ADDRESS_EXPIRED_TIME, "true");
        }catch (Exception e){
            e.printStackTrace();
            failedReason = e.getLocalizedMessage();
            result = ImmutableMap.of("file", exported_file, "email", content, "subject", subject);
        }

        //保存邮寄记录
        {
            MailRecord record = MailRecord.of(staff.getId(), exported_file, mailAddress, content);

            record.setTypeID(UnionTypeID.of(evaluateRecordId, 1));
            if (result != null) {
                record.setSentResult("失败，原因：" + failedReason);
            }
            mailRecordRepository.save(record);
        }
        return result;
    }
}
